#!/usr/bin/env python3
import os
import subprocess
import sys
import platform
import shutil
import json
import re
from pathlib import Path
from typing import Dict, List, Optional, Any


class Vue3TsViteFullExample:
    def __init__(self):
        self.project_name = ""
        self.port = 3000
        self.need_proxy = False
        self.proxy_config = {}
        self.project_dir = ""
        self.npm_cmd = "npm.cmd" if platform.system() == "Windows" else "npm"
        self.package_manager = "npm"  # 支持 npm, pnpm, yarn

        # 扩展的可选模块
        self.optional_modules = {
            "1": {"name": "Vue Router", "packages": ["vue-router@4"], "selected": False},
            "2": {"name": "Pinia", "packages": ["pinia"], "selected": False},
            "3": {"name": "ESLint + Prettier",
                  "packages": ["eslint", "eslint-plugin-vue", "@typescript-eslint/eslint-plugin",
                               "@typescript-eslint/parser", "prettier", "eslint-config-prettier"], "selected": False},
            "4": {"name": "Axios", "packages": ["axios"], "selected": False},
            "5": {"name": "VueUse", "packages": ["@vueuse/core"], "selected": False},
            "6": {"name": "Tailwind CSS", "packages": ["tailwindcss", "postcss", "autoprefixer"], "selected": False},
            "7": {"name": "Element Plus",
                  "packages": ["element-plus", "unplugin-vue-components", "unplugin-auto-import"], "selected": False},
            "8": {"name": "Ant Design Vue", "packages": ["ant-design-vue", "unplugin-vue-components"],
                  "selected": False},
            "9": {"name": "Vitest (测试框架)", "packages": ["vitest", "@vue/test-utils", "jsdom"], "selected": False},
            "10": {"name": "Sass/SCSS", "packages": ["sass"], "selected": False},
            "11": {"name": "Lodash", "packages": ["lodash", "@types/lodash"], "selected": False},
            "12": {"name": "Day.js", "packages": ["dayjs"], "selected": False},
            "13": {"name": "Iconify", "packages": ["@iconify/vue"], "selected": False},
            "14": {"name": "Mock.js", "packages": ["mockjs", "@types/mockjs", "vite-plugin-mock"], "selected": False}
        }

    def run(self):
        """主运行流程"""
        try:
            self.print_banner()
            self.detect_package_manager()
            self.collect_user_input()
            self.ask_optional_modules()
            self.create_project()
            self.install_dependencies()
            self.configure_vite()
            self.generate_examples()
            self.optional_module_config()
            self.generate_config_files()
            self.print_success()
        except KeyboardInterrupt:
            print("\n\n❌ 用户取消操作")
            sys.exit(1)
        except Exception as e:
            print(f"\n❌ 创建项目时发生错误: {e}")
            sys.exit(1)

    def print_banner(self):
        """打印欢迎横幅"""
        banner = """
╔══════════════════════════════════════════════════════════════╗
║                   Vue3 + TypeScript + Vite                  ║
║                    智能脚手架生成器 v2.0                      ║
║                                                              ║
║  🚀 快速创建现代化 Vue3 项目                                 ║
║  ⚡️ 支持多种包管理器和可选模块                               ║
║  🎯 开箱即用的最佳实践配置                                   ║
╚══════════════════════════════════════════════════════════════╝
        """
        print(banner)

    def detect_package_manager(self):
        """检测可用的包管理器"""
        managers = ["pnpm", "yarn", "npm"]
        available = []

        for manager in managers:
            try:
                subprocess.run([manager, "--version"], capture_output=True, check=True)
                available.append(manager)
            except (subprocess.CalledProcessError, FileNotFoundError):
                continue

        if not available:
            print("❌ 未找到任何包管理器，请安装 npm、yarn 或 pnpm")
            sys.exit(1)

        if len(available) > 1:
            print("🔍 检测到多个包管理器:")
            for i, manager in enumerate(available, 1):
                print(f"  [{i}] {manager}")

            while True:
                choice = input(f"请选择包管理器 (1-{len(available)}, 默认: {available[0]}): ").strip()
                if not choice:
                    self.package_manager = available[0]
                    break
                try:
                    idx = int(choice) - 1
                    if 0 <= idx < len(available):
                        self.package_manager = available[idx]
                        break
                    else:
                        print("❌ 选择无效，请重新输入")
                except ValueError:
                    print("❌ 请输入数字")
        else:
            self.package_manager = available[0]

        print(f"📦 使用包管理器: {self.package_manager}")

        # 更新命令
        if self.package_manager == "npm":
            self.npm_cmd = "npm.cmd" if platform.system() == "Windows" else "npm"
        else:
            self.npm_cmd = self.package_manager

    def collect_user_input(self):
        """收集用户输入"""
        print("\n📋 项目配置")
        print("-" * 50)

        # 项目名称
        while True:
            self.project_name = input("📁 项目名称: ").strip()
            if not self.project_name:
                print("❌ 项目名称不能为空")
                continue
            if not re.match(r'^[a-zA-Z0-9_-]+$', self.project_name):
                print("❌ 项目名称只能包含字母、数字、下划线和连字符")
                continue
            if Path(self.project_name).exists():
                overwrite = input(f"⚠️ 目录 {self.project_name} 已存在，是否覆盖？(y/n): ").strip().lower()
                if overwrite == 'y':
                    shutil.rmtree(self.project_name)
                    break
                else:
                    continue
            break

        # 开发端口
        while True:
            port_input = input("🌐 开发端口（默认 3000）: ").strip()
            if not port_input:
                self.port = 3000
                break
            try:
                port = int(port_input)
                if 1 <= port <= 65535:
                    self.port = port
                    break
                else:
                    print("❌ 端口号应在 1-65535 范围内")
            except ValueError:
                print("❌ 端口号必须是数字")

        # 代理配置
        proxy = input("🌍 是否配置开发代理？(y/n, 默认: n): ").strip().lower()
        self.need_proxy = proxy == 'y'
        if self.need_proxy:
            self.configure_proxy()

    def ask_optional_modules(self):
        """询问可选模块"""
        print("\n📦 可选模块")
        print("-" * 50)
        print("请选择需要的模块（输入编号，用逗号分隔，如: 1,2,4）:")
        print()

        # 按类别组织显示
        ui_libs = ["7", "8"]  # Element Plus, Ant Design Vue
        dev_tools = ["3", "9", "14"]  # ESLint, Vitest, Mock
        utils = ["4", "5", "11", "12", "13"]  # Axios, VueUse, Lodash, Day.js, Iconify
        styling = ["6", "10"]  # Tailwind, Sass
        core = ["1", "2"]  # Router, Pinia

        print("🎯 核心功能:")
        for key in core:
            mod = self.optional_modules[key]
            print(f"  [{key}] {mod['name']}")

        print("\n🎨 样式工具:")
        for key in styling:
            mod = self.optional_modules[key]
            print(f"  [{key}] {mod['name']}")

        print("\n🧩 UI 组件库:")
        for key in ui_libs:
            mod = self.optional_modules[key]
            print(f"  [{key}] {mod['name']}")

        print("\n🛠️ 开发工具:")
        for key in dev_tools:
            mod = self.optional_modules[key]
            print(f"  [{key}] {mod['name']}")

        print("\n📚 工具库:")
        for key in utils:
            mod = self.optional_modules[key]
            print(f"  [{key}] {mod['name']}")

        print("\n💡 推荐组合:")
        print("  基础版: 1,2,3,4")
        print("  完整版: 1,2,3,4,5,6,9")
        print("  企业版: 1,2,3,4,5,7,9,11,12")

        selection = input("\n输入模块编号: ").strip()
        if selection:
            for key in selection.split(","):
                key = key.strip()
                if key in self.optional_modules:
                    self.optional_modules[key]["selected"] = True
                else:
                    print(f"⚠️ 模块编号 {key} 无效，已跳过")

    def configure_proxy(self):
        """配置代理"""
        print("\n🌐 代理配置")
        print("-" * 30)
        print("输入代理规则（输入空行结束）:")

        while True:
            prefix = input("请输入代理前缀（如 /api）: ").strip()
            if not prefix:
                break

            if not prefix.startswith('/'):
                prefix = '/' + prefix

            target = input(f"请输入 {prefix} 对应的目标地址（如 http://localhost:8080）: ").strip()
            if not target:
                print("❌ 目标地址不能为空")
                continue

            # 验证目标地址格式
            if not re.match(r'^https?://', target):
                print("❌ 目标地址必须以 http:// 或 https:// 开头")
                continue

            # 可选配置
            change_origin = input("是否更改 Origin 头？(y/n, 默认: y): ").strip().lower()
            change_origin = change_origin != 'n'

            rewrite_rule = input(f"是否重写路径？(y/n, 默认: y): ").strip().lower()
            rewrite_rule = rewrite_rule != 'n'

            self.proxy_config[prefix] = {
                "target": target,
                "changeOrigin": change_origin,
                "rewrite": f"(path) => path.replace(/^{re.escape(prefix)}/, '')" if rewrite_rule else None
            }

            print(f"✅ 已添加代理: {prefix} -> {target}")

    def create_project(self):
        print(f"📁 创建项目 {self.project_name} ...")
        try:
            subprocess.run(
                [self.npm_cmd, "create", "vite@latest", self.project_name, "--", "--template", "vue-ts"],
                check=True
            )
            self.project_dir = str(Path.cwd() / self.project_name)
        except subprocess.CalledProcessError as e:
            print("❌ 项目创建失败:", e)
            sys.exit(1)

    def install_dependencies(self):
        """安装依赖"""
        print("\n📦 安装依赖...")
        os.chdir(self.project_dir)

        # 基础依赖
        self.safe_install(["install"])

        # 升级 Vite 和 Vue 插件到稳定版本
        dev_deps = [
            "vite@latest",
            "@vitejs/plugin-vue@latest",
            "typescript@latest",
            "@vue/tsconfig@latest"
        ]
        self.safe_install(["install", "--save-dev"] + dev_deps)

        # 安装选中的模块
        for mod in self.optional_modules.values():
            if mod["selected"]:
                if mod["name"] == "Vitest (测试框架)":
                    self.safe_install(["install", "--save-dev"] + mod["packages"])
                else:
                    self.safe_install(["install"] + mod["packages"])

    def configure_vite(self):
        """配置 Vite"""
        print("⚙️ 配置 Vite...")
        config_path = Path("test/vite.config.ts")

        imports = [
            "import { defineConfig } from 'vite'",
            "import vue from '@vitejs/plugin-vue'"
        ]

        plugins = ["vue()"]

        # 根据选中的模块添加插件
        if self.optional_modules["7"]["selected"]:  # Element Plus
            imports.append("import Components from 'unplugin-vue-components/vite'")
            imports.append("import AutoImport from 'unplugin-auto-import/vite'")
            imports.append("import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'")
            plugins.extend([
                "Components({ resolvers: [ElementPlusResolver()] })",
                "AutoImport({ resolvers: [ElementPlusResolver()] })"
            ])

        if self.optional_modules["8"]["selected"]:  # Ant Design Vue
            imports.append("import Components from 'unplugin-vue-components/vite'")
            imports.append("import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'")
            plugins.append("Components({ resolvers: [AntDesignVueResolver()] })")

        if self.optional_modules["14"]["selected"]:  # Mock
            imports.append("import { viteMockServe } from 'vite-plugin-mock'")
            plugins.append("viteMockServe({ mockPath: 'mock' })")

        # 生成代理配置
        proxy_config = ""
        if self.need_proxy and self.proxy_config:
            proxy_items = []
            for prefix, config in self.proxy_config.items():
                proxy_item = f"'{prefix}': {{\n"
                proxy_item += f"      target: '{config['target']}',\n"
                proxy_item += f"      changeOrigin: {str(config['changeOrigin']).lower()},\n"
                if config.get('rewrite'):
                    proxy_item += f"      rewrite: {config['rewrite']}\n"
                proxy_item += "    }"
                proxy_items.append(proxy_item)

            proxy_body = "\n    ".join(proxy_items)
            proxy_config = f"    proxy: {{\n    {proxy_body}\n    }},\n"

        # 生成配置文件内容
        content = f"""{chr(10).join(imports)}

export default defineConfig({{
  plugins: [
    {f',{chr(10)}    '.join(plugins)}
  ],
  server: {{
    port: {self.port},
    open: true,
    host: '0.0.0.0',
{proxy_config}  }},
  build: {{
    target: 'es2015',
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: false,
    minify: 'terser'
  }},
  resolve: {{
    alias: {{
      '@': new URL('./src', import.meta.url).pathname
    }}
  }}
}})
"""
        config_path.write_text(content, encoding="utf-8")
        print("✅ Vite 配置完成")

    def generate_examples(self):
        """生成示例代码"""
        print("🎯 生成示例代码...")

        # 创建目录结构
        directories = [
            "src/components",
            "src/views",
            "src/utils",
            "src/types",
            "src/assets/styles"
        ]

        if self.optional_modules["1"]["selected"]:  # Router
            directories.append("src/router")
        if self.optional_modules["2"]["selected"]:  # Pinia
            directories.append("src/stores")
        if self.optional_modules["14"]["selected"]:  # Mock
            directories.append("mock")

        for dir_path in directories:
            Path(dir_path).mkdir(parents=True, exist_ok=True)

        # 生成核心文件
        self.create_app_vue()
        self.create_main_ts()
        self.create_types()

        # 根据选中模块生成对应文件
        if self.optional_modules["1"]["selected"]:
            self.create_router_example()
        if self.optional_modules["2"]["selected"]:
            self.create_pinia_example()
        if self.optional_modules["4"]["selected"]:
            self.create_axios_example()
        if self.optional_modules["9"]["selected"]:
            self.create_test_example()
        if self.optional_modules["14"]["selected"]:
            self.create_mock_example()

    def create_app_vue(self):
        """创建 App.vue"""
        router_view = '<router-view />' if self.optional_modules["1"]["selected"] else '<Home />'

        app_vue_content = f'''<template>
  <div id="app">
    <header class="app-header">
      <h1>🚀 Vue3 + TypeScript + Vite</h1>
      <p>现代化前端开发脚手架</p>
    </header>

    <main class="app-main">
      {router_view}
    </main>

    <footer class="app-footer">
      <p>Powered by Vue3 + Vite ⚡️</p>
    </footer>
  </div>
</template>

<script setup lang="ts">
import {{ onMounted }} from 'vue'
{"import Home from './views/Home.vue'" if not self.optional_modules["1"]["selected"] else ""}

onMounted(() => {{
  console.log('🎉 应用已启动')
}})
</script>

<style scoped>
.app-header {{
  text-align: center;
  padding: 2rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  margin-bottom: 2rem;
}}

.app-header h1 {{
  margin: 0 0 0.5rem 0;
  font-size: 2rem;
}}

.app-main {{
  min-height: 60vh;
  padding: 0 1rem;
}}

.app-footer {{
  text-align: center;
  padding: 1rem;
  color: #666;
  border-top: 1px solid #eee;
  margin-top: 2rem;
}}
</style>
'''
        Path("test/src/App.vue").write_text(app_vue_content, encoding="utf-8")

    def create_main_ts(self):
        """创建 main.ts"""
        imports = [
            "import { createApp } from 'vue'",
            "import App from './App.vue'"
        ]

        if self.optional_modules["1"]["selected"]:
            imports.append("import router from './router'")
        if self.optional_modules["2"]["selected"]:
            imports.append("import { createPinia } from 'pinia'")
        if self.optional_modules["6"]["selected"]:
            imports.append("import './assets/styles/index.css'")
        if self.optional_modules["7"]["selected"]:
            imports.append("import 'element-plus/dist/index.css'")
        if self.optional_modules["8"]["selected"]:
            imports.append("import 'ant-design-vue/dist/antd.css'")
        if self.optional_modules["10"]["selected"]:
            imports.append("import './assets/styles/main.scss'")

        setup_code = ["const app = createApp(App)"]

        if self.optional_modules["2"]["selected"]:
            setup_code.append("app.use(createPinia())")
        if self.optional_modules["1"]["selected"]:
            setup_code.append("app.use(router)")

        setup_code.append("app.mount('#app')")

        content = f"""{chr(10).join(imports)}

{chr(10).join(setup_code)}
"""
        Path("test/src/main.ts").write_text(content, encoding="utf-8")

    def create_types(self):
        """创建类型定义"""
        global_types = '''// 全局类型定义
export interface ApiResponse<T = any> {
  code: number
  data: T
  message: string
}

export interface User {
  id: number
  name: string
  email: string
  avatar?: string
}

export interface PaginationParams {
  page: number
  pageSize: number
}

export interface PaginationResult<T> {
  list: T[]
  total: number
  page: number
  pageSize: number
}
'''
        Path("src/types/global.ts").write_text(global_types, encoding="utf-8")

    def create_router_example(self):
        """创建路由示例"""
        router_content = '''import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    meta: { title: '首页' }
  },
  {
    path: '/about',
    name: 'About',
    component: About,
    meta: { title: '关于' }
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

// 路由守卫
router.beforeEach((to, from, next) => {
  document.title = `${to.meta.title} - Vue3 App`
  next()
})

export default router
'''
        Path("test/src/router/index.ts").write_text(router_content, encoding="utf-8")

        # 创建页面组件
        home_vue = '''<template>
  <div class="home">
    <h2>🏠 首页</h2>
    <div class="feature-grid">
      <div class="feature-card">
        <h3>⚡️ 快速开发</h3>
        <p>基于 Vite 的快速热重载</p>
      </div>
      <div class="feature-card">
        <h3>🎯 类型安全</h3>
        <p>TypeScript 提供完整类型支持</p>
      </div>
      <div class="feature-card">
        <h3>📦 模块化</h3>
        <p>可选的功能模块，按需引入</p>
      </div>
    </div>
    <router-link to="/about" class="nav-link">→ 了解更多</router-link>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'

onMounted(() => {
  console.log('Home page mounted')
})
</script>

<style scoped>
.home {
  max-width: 800px;
  margin: 0 auto;
  text-align: center;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 2rem;
  margin: 2rem 0;
}

.feature-card {
  padding: 1.5rem;
  border: 1px solid #eee;
  border-radius: 8px;
  background: #f9f9f9;
}

.nav-link {
  display: inline-block;
  margin-top: 2rem;
  padding: 0.5rem 1rem;
  background: #667eea;
  color: white;
  text-decoration: none;
  border-radius: 4px;
  transition: background 0.3s;
}

.nav-link:hover {
  background: #5a6fd8;
}
</style>
'''
        Path("src/views/Home.vue").write_text(home_vue, encoding="utf-8")

        about_vue = '''<template>
  <div class="about">
    <h2>📖 关于项目</h2>
    <div class="content">
      <p>这是一个基于 Vue3 + TypeScript + Vite 的现代化前端项目模板。</p>
      <ul>
        <li>🚀 Vite 构建工具，开发体验极佳</li>
        <li>⚡️ Vue3 Composition API</li>
        <li>🎯 TypeScript 类型安全</li>
        <li>📦 可选的功能模块</li>
      </ul>
      <router-link to="/" class="back-link">← 返回首页</router-link>
    </div>
  </div>
</template>

<script setup lang="ts">
// 组件逻辑
</script>

<style scoped>
.about {
  max-width: 600px;
  margin: 0 auto;
  text-align: center;
}

.content {
  text-align: left;
  margin: 2rem 0;
}

.content ul {
  margin: 1rem 0;
  padding-left: 2rem;
}

.content li {
  margin: 0.5rem 0;
}

.back-link {
  display: inline-block;
  margin-top: 2rem;
  padding: 0.5rem 1rem;
  background: #667eea;
  color: white;
  text-decoration: none;
  border-radius: 4px;
}
</style>
'''
        Path("src/views/About.vue").write_text(about_vue, encoding="utf-8")

    def create_pinia_example(self):
        """创建 Pinia 示例"""
        counter_store = '''import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  // 状态
  const count = ref(0)

  // 计算属性
  const doubleCount = computed(() => count.value * 2)

  // 方法
  const increment = () => {
    count.value++
  }

  const decrement = () => {
    count.value--
  }

  const reset = () => {
    count.value = 0
  }

  return {
    count,
    doubleCount,
    increment,
    decrement,
    reset
  }
})
'''
        Path("test/src/stores/counter.ts").write_text(counter_store, encoding="utf-8")

        user_store = '''import { defineStore } from 'pinia'
import { ref } from 'vue'
import type { User } from '@/types/global'

export const useUserStore = defineStore('user', () => {
  const user = ref<User | null>(null)
  const loading = ref(false)

  const setUser = (userData: User) => {
    user.value = userData
  }

  const clearUser = () => {
    user.value = null
  }

  const login = async (email: string, password: string) => {
    loading.value = true
    try {
      // 模拟 API 调用
      await new Promise(resolve => setTimeout(resolve, 1000))
      const userData: User = {
        id: 1,
        name: '测试用户',
        email
      }
      setUser(userData)
      return userData
    } finally {
      loading.value = false
    }
  }

  return {
    user,
    loading,
    setUser,
    clearUser,
    login
  }
})
'''
        Path("src/stores/user.ts").write_text(user_store, encoding="utf-8")

    def create_axios_example(self):
        """创建 Axios 示例"""
        axios_config = '''import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import type { ApiResponse } from '@/types/global'

// 创建 axios 实例
const instance: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
})

// 请求拦截器
instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    // 可以在这里添加 token
    const token = localStorage.getItem('token')
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
instance.interceptors.response.use(
  (response: AxiosResponse<ApiResponse>) => {
    const { data } = response
    if (data.code === 200) {
      return data.data
    } else {
      throw new Error(data.message || '请求失败')
    }
  },
  (error) => {
    const message = error.response?.data?.message || error.message || '网络错误'
    console.error('API Error:', message)
    return Promise.reject(new Error(message))
  }
)

export default instance
'''
        Path("src/utils/request.ts").write_text(axios_config, encoding="utf-8")

        # 创建 API 示例
        api_example = '''import request from './request'
import type { User, PaginationParams, PaginationResult } from '@/types/global'

// 用户相关 API
export const userApi = {
  // 获取用户列表
  getUsers: (params: PaginationParams) => 
    request.get<PaginationResult<User>>('/users', { params }),

  // 获取用户详情
  getUserById: (id: number) => 
    request.get<User>(`/users/${id}`),

  // 创建用户
  createUser: (data: Omit<User, 'id'>) => 
    request.post<User>('/users', data),

  // 更新用户
  updateUser: (id: number, data: Partial<User>) => 
    request.put<User>(`/users/${id}`, data),

  // 删除用户
  deleteUser: (id: number) => 
    request.delete(`/users/${id}`)
}

// 认证相关 API
export const authApi = {
  login: (email: string, password: string) =>
    request.post<{ token: string; user: User }>('/auth/login', { email, password }),

  logout: () => 
    request.post('/auth/logout'),

  refreshToken: () => 
    request.post<{ token: string }>('/auth/refresh')
}
'''
        Path("src/utils/api.ts").write_text(api_example, encoding="utf-8")

    def create_test_example(self):
        """创建测试示例"""
        # 创建 vitest 配置
        vitest_config = '''/// <reference types="vitest" />
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts'
  },
  resolve: {
    alias: {
      '@': new URL('./src', import.meta.url).pathname
    }
  }
})
'''
        Path("vitest.config.ts").write_text(vitest_config, encoding="utf-8")

        # 创建测试目录
        Path("src/test").mkdir(exist_ok=True)

        # 测试设置文件
        test_setup = '''import { expect, afterEach } from 'vitest'
import { cleanup } from '@vue/test-utils'
import * as matchers from '@testing-library/jest-dom/matchers'

// 扩展 expect
expect.extend(matchers)

// 每个测试后清理
afterEach(() => {
  cleanup()
})
'''
        Path("src/test/setup.ts").write_text(test_setup, encoding="utf-8")

        # 示例测试
        if self.optional_modules["2"]["selected"]:  # Pinia
            counter_test = '''import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useCounterStore } from '@/stores/counter'

describe('Counter Store', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('should increment count', () => {
    const counter = useCounterStore()
    expect(counter.count).toBe(0)

    counter.increment()
    expect(counter.count).toBe(1)
  })

  it('should decrement count', () => {
    const counter = useCounterStore()
    counter.increment()
    counter.decrement()
    expect(counter.count).toBe(0)
  })

  it('should reset count', () => {
    const counter = useCounterStore()
    counter.increment()
    counter.increment()
    counter.reset()
    expect(counter.count).toBe(0)
  })

  it('should calculate double count', () => {
    const counter = useCounterStore()
    counter.increment()
    counter.increment()
    expect(counter.doubleCount).toBe(4)
  })
})
'''
            Path("src/test/counter.test.ts").write_text(counter_test, encoding="utf-8")

        # 组件测试示例
        component_test = '''import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'

const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/', component: Home }]
})

describe('Home Component', () => {
  it('should render home page', async () => {
    const wrapper = mount(Home, {
      global: {
        plugins: [router]
      }
    })

    expect(wrapper.find('h2').text()).toBe('🏠 首页')
    expect(wrapper.find('.feature-grid').exists()).toBe(true)
  })
})
'''
        Path("src/test/Home.test.ts").write_text(component_test, encoding="utf-8")

    def create_mock_example(self):
        """创建 Mock 示例"""
        mock_users = '''import { MockMethod } from 'vite-plugin-mock'
import type { User, ApiResponse, PaginationResult } from '../src/types/global'

const users: User[] = [
  { id: 1, name: '张三', email: 'zhangsan@example.com' },
  { id: 2, name: '李四', email: 'lisi@example.com' },
  { id: 3, name: '王五', email: 'wangwu@example.com' }
]

export default [
  // 获取用户列表
  {
    url: '/api/users',
    method: 'get',
    response: ({ query }) => {
      const page = Number(query.page) || 1
      const pageSize = Number(query.pageSize) || 10
      const start = (page - 1) * pageSize
      const end = start + pageSize

      const result: ApiResponse<PaginationResult<User>> = {
        code: 200,
        message: '成功',
        data: {
          list: users.slice(start, end),
          total: users.length,
          page,
          pageSize
        }
      }
      return result
    }
  },

  // 获取用户详情
  {
    url: '/api/users/:id',
    method: 'get',
    response: ({ url }) => {
      const id = Number(url.split('/').pop())
      const user = users.find(u => u.id === id)

      if (user) {
        return {
          code: 200,
          message: '成功',
          data: user
        }
      } else {
        return {
          code: 404,
          message: '用户不存在',
          data: null
        }
      }
    }
  },

  // 登录
  {
    url: '/api/auth/login',
    method: 'post',
    response: ({ body }) => {
      const { email, password } = body

      if (email === 'admin@example.com' && password === '123456') {
        return {
          code: 200,
          message: '登录成功',
          data: {
            token: 'mock-token-' + Date.now(),
            user: { id: 1, name: '管理员', email }
          }
        }
      } else {
        return {
          code: 401,
          message: '邮箱或密码错误',
          data: null
        }
      }
    }
  }
] as MockMethod[]
'''
        Path("mock/users.ts").write_text(mock_users, encoding="utf-8")

    def optional_module_config(self):
        """配置可选模块"""
        print("🔧 配置可选模块...")

        # ESLint + Prettier
        if self.optional_modules["3"]["selected"]:
            self.setup_eslint_prettier()

        # Tailwind CSS
        if self.optional_modules["6"]["selected"]:
            self.setup_tailwind()

        # Sass
        if self.optional_modules["10"]["selected"]:
            self.setup_sass()

    def setup_eslint_prettier(self):
        """设置 ESLint 和 Prettier"""
        eslint_config = '''{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": [
    "eslint:recommended",
    "@typescript-eslint/recommended",
    "plugin:vue/vue3-essential",
    "prettier"
  ],
  "parser": "vue-eslint-parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "parser": "@typescript-eslint/parser",
    "sourceType": "module"
  },
  "plugins": [
    "vue",
    "@typescript-eslint"
  ],
  "rules": {
    "vue/multi-word-component-names": "off",
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/no-explicit-any": "warn"
  }
}
'''
        Path(".eslintrc.json").write_text(eslint_config, encoding="utf-8")

        prettier_config = '''{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100,
  "bracketSpacing": true,
  "arrowParens": "avoid"
}
'''
        Path(".prettierrc").write_text(prettier_config, encoding="utf-8")

    def setup_tailwind(self):
        """设置 Tailwind CSS"""
        try:
            subprocess.run([
                "npx", "tailwindcss", "init", "-p"
            ], check=True, capture_output=True)

            # 更新 tailwind.config.js
            tailwind_config = '''/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
'''
            Path("tailwind.config.js").write_text(tailwind_config, encoding="utf-8")

            # 创建 CSS 文件
            Path("src/assets/styles").mkdir(parents=True, exist_ok=True)
            css_content = '''@tailwind base;
@tailwind components;
@tailwind utilities;

/* 自定义样式 */
@layer components {
  .btn {
    @apply px-4 py-2 rounded-lg font-medium transition-colors;
  }

  .btn-primary {
    @apply bg-blue-500 text-white hover:bg-blue-600;
  }

  .btn-secondary {
    @apply bg-gray-500 text-white hover:bg-gray-600;
  }
}
'''
            Path("src/assets/styles/index.css").write_text(css_content, encoding="utf-8")

        except Exception as e:
            print(f"⚠️ Tailwind 初始化失败: {e}")

    def setup_sass(self):
        """设置 Sass"""
        Path("src/assets/styles").mkdir(parents=True, exist_ok=True)

        # 创建主 SCSS 文件
        main_scss = '''// 变量
$primary-color: #667eea;
$secondary-color: #764ba2;
$text-color: #333;
$background-color: #f5f5f5;

// 混合器
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin button-style($bg-color, $text-color: white) {
  background-color: $bg-color;
  color: $text-color;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s ease;

  &:hover {
    background-color: darken($bg-color, 10%);
  }
}

// 全局样式
* {
  box-sizing: border-box;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  color: $text-color;
  background-color: $background-color;
  margin: 0;
  padding: 0;
}

// 工具类
.text-center {
  text-align: center;
}

.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-3 { margin-top: 1rem; }
.mt-4 { margin-top: 1.5rem; }

.btn {
  @include button-style($primary-color);
}

.btn-secondary {
  @include button-style($secondary-color);
}
'''
        Path("src/assets/styles/main.scss").write_text(main_scss, encoding="utf-8")

    def generate_config_files(self):
        """生成配置文件"""
        print("📝 生成配置文件...")

        # 环境变量文件
        env_content = '''# 开发环境变量
VITE_API_BASE_URL=http://localhost:3001/api
VITE_APP_NAME=Vue3 App
VITE_APP_VERSION=1.0.0
'''
        Path(".env.development").write_text(env_content, encoding="utf-8")

        env_prod_content = '''# 生产环境变量
VITE_API_BASE_URL=https://api.example.com
VITE_APP_NAME=Vue3 App
VITE_APP_VERSION=1.0.0
'''
        Path(".env.production").write_text(env_prod_content, encoding="utf-8")

        # 更新 package.json 脚本
        package_json_path = Path("test/package.json")
        if package_json_path.exists():
            with open(package_json_path, 'r', encoding='utf-8') as f:
                package_data = json.load(f)

            # 添加脚本
            scripts = {
                "dev": "vite",
                "build": "vue-tsc && vite build",
                "preview": "vite preview",
                "type-check": "vue-tsc --noEmit"
            }

            if self.optional_modules["3"]["selected"]:  # ESLint
                scripts.update({
                    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
                    "format": "prettier --write src/"
                })

            if self.optional_modules["9"]["selected"]:  # Vitest
                scripts.update({
                    "test": "vitest",
                    "test:ui": "vitest --ui",
                    "coverage": "vitest run --coverage"
                })

            package_data["scripts"] = scripts

            with open(package_json_path, 'w', encoding='utf-8') as f:
                json.dump(package_data, f, indent=2, ensure_ascii=False)

        # tsconfig.json 优化
        tsconfig_content = '''{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
'''
        Path("test/tsconfig.json").write_text(tsconfig_content, encoding="utf-8")

        # README.md
        readme_content = f'''# {self.project_name}

基于 Vue3 + TypeScript + Vite 的现代化前端项目

## 🚀 特性

- ⚡️ [Vite](https://vitejs.dev/) - 极速的构建工具
- 🖖 [Vue 3](https://vuejs.org/) - 渐进式 JavaScript 框架
- 🎯 [TypeScript](https://www.typescriptlang.org/) - JavaScript 的超集
{"- 🛣️ [Vue Router](https://router.vuejs.org/) - 官方路由管理器" if self.optional_modules["1"]["selected"] else ""}
{"- 🍍 [Pinia](https://pinia.vuejs.org/) - 新一代状态管理" if self.optional_modules["2"]["selected"] else ""}
{"- 📏 [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) - 代码规范" if self.optional_modules["3"]["selected"] else ""}
{"- 📱 [Axios](https://axios-http.com/) - HTTP 请求库" if self.optional_modules["4"]["selected"] else ""}
{"- 🎨 [Tailwind CSS](https://tailwindcss.com/) - 原子化 CSS 框架" if self.optional_modules["6"]["selected"] else ""}
{"- 🧪 [Vitest](https://vitest.dev/) - 基于 Vite 的测试框架" if self.optional_modules["9"]["selected"] else ""}

## 📦 安装

```bash
# 使用 {self.package_manager}
{self.package_manager} install
```

## 🛠️ 开发

```bash
# 启动开发服务器
{self.package_manager} run dev
```

## 🏗️ 构建

```bash
# 构建生产版本
{self.package_manager} run build

# 预览构建结果
{self.package_manager} run preview
```

{"## 🧪 测试" if self.optional_modules["9"]["selected"] else ""}
{"```bash" if self.optional_modules["9"]["selected"] else ""}
{"# 运行测试" if self.optional_modules["9"]["selected"] else ""}
{f"{self.package_manager} run test" if self.optional_modules["9"]["selected"] else ""}
{"```" if self.optional_modules["9"]["selected"] else ""}

{"## 📏 代码规范" if self.optional_modules["3"]["selected"] else ""}
{"```bash" if self.optional_modules["3"]["selected"] else ""}
{"# 代码检查" if self.optional_modules["3"]["selected"] else ""}
{f"{self.package_manager} run lint" if self.optional_modules["3"]["selected"] else ""}
{"" if not self.optional_modules["3"]["selected"] else ""}
{"# 代码格式化" if self.optional_modules["3"]["selected"] else ""}
{f"{self.package_manager} run format" if self.optional_modules["3"]["selected"] else ""}
{"```" if self.optional_modules["3"]["selected"] else ""}

## 📁 项目结构

```
{self.project_name}/
├── public/          # 静态资源
├── src/
│   ├── assets/      # 资源文件
│   ├── components/  # 组件
│   ├── views/       # 页面
{"│   ├── router/     # 路由配置" if self.optional_modules["1"]["selected"] else ""}
{"│   ├── stores/     # 状态管理" if self.optional_modules["2"]["selected"] else ""}
│   ├── utils/       # 工具函数
│   ├── types/       # 类型定义
│   ├── App.vue      # 根组件
│   └── main.ts      # 入口文件
├── index.html       # HTML 模板
├── vite.config.ts   # Vite 配置
└── package.json     # 依赖配置
```

## 🤝 贡献

欢迎提交 Issue 和 Pull Request！

## 📄 许可证

[MIT](./LICENSE)
'''
        Path("test/README.md").write_text(readme_content, encoding="utf-8")

    def safe_install(self, args: List[str], cwd: Optional[str] = None):
        """安全安装依赖"""
        cmd_args = []

        if self.package_manager == "npm":
            cmd_args = [self.npm_cmd] + args + ["--silent"]
        elif self.package_manager == "pnpm":
            cmd_args = ["pnpm"] + args
        elif self.package_manager == "yarn":
            # yarn 的命令格式不同
            if "install" in args:
                if len(args) == 1:  # 只有 install
                    cmd_args = ["yarn", "install"]
                else:  # 安装具体包
                    cmd_args = ["yarn", "add"] + [arg for arg in args if arg != "install"]
                    if "--save-dev" in args:
                        cmd_args = ["yarn", "add", "--dev"] + [arg for arg in args if
                                                               arg not in ["install", "--save-dev"]]

        try:
            print(f"🔄 {' '.join(args)}")
            result = subprocess.run(
                cmd_args,
                check=True,
                cwd=cwd or self.project_dir,
                capture_output=True,
                text=True
            )
            return True
        except subprocess.CalledProcessError as e:
            print(f"❌ 安装失败: {' '.join(args)}")
            if e.stderr:
                print(f"错误信息: {e.stderr}")
            return False

    def print_success(self):
        """打印成功信息"""
        selected_modules = [mod["name"] for mod in self.optional_modules.values() if mod["selected"]]

        success_banner = f"""
╔══════════════════════════════════════════════════════════════╗
║                        🎉 创建成功！                         ║
╚══════════════════════════════════════════════════════════════╝

📁 项目位置: {self.project_dir}
🌐 开发端口: {self.port}
📦 包管理器: {self.package_manager}

🎯 已安装的模块:
"""

        if selected_modules:
            for module in selected_modules:
                success_banner += f"  ✅ {module}\n"
        else:
            success_banner += "  📦 基础配置\n"

        success_banner += f"""
🚀 快速开始:
  cd {self.project_name}
  {self.package_manager} run dev

🛠️ 其他命令:
  {self.package_manager} run build     # 构建生产版本
  {self.package_manager} run preview   # 预览构建结果"""

        if self.optional_modules["3"]["selected"]:
            success_banner += f"""
  {self.package_manager} run lint      # 代码检查
  {self.package_manager} run format    # 代码格式化"""

        if self.optional_modules["9"]["selected"]:
            success_banner += f"""
  {self.package_manager} run test      # 运行测试"""

        success_banner += """

📖 更多信息请查看 README.md

祝您开发愉快！🎊
"""

        print(success_banner)


if __name__ == "__main__":
    try:
        Vue3TsViteFullExample().run()
    except KeyboardInterrupt:
        print("\n\n👋 再见！")
    except Exception as e:
        print(f"\n❌ 程序执行失败: {e}")
        sys.exit(1)